package com.dlc.shop.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.enums.RemindType;
import com.dlc.shop.bean.enums.SendType;
import com.dlc.shop.bean.model.NotifyLog;
import com.dlc.shop.bean.param.NotifyTemplateParam;
import com.dlc.shop.bean.param.OrderParam;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.enums.WxMsgReturnCode;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.util.Json;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.config.ShopConfig;
import com.dlc.shop.config.WxConfig;
import com.dlc.shop.dao.NotifyLogMapper;
import com.dlc.shop.service.NotifyLogService;
import com.dlc.shop.service.SmsLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author lhd
 * @date 2020-07-01 15:44:27
 */
@Slf4j
@Service
@AllArgsConstructor
public class NotifyLogServiceImpl extends ServiceImpl<NotifyLogMapper, NotifyLog> implements NotifyLogService {

    private final NotifyLogMapper notifyLogMapper;
    private final SmsLogService smsLogService;
    private final ShopConfig shopConfig;
    private final WxConfig wxConfig;

    private final static String NO_DELIVERY = "无需快递";

    @Override
    public IPage<NotifyLog> pageByParam(PageParam<NotifyLog> page, OrderParam orderParam) {
        IPage<NotifyLog> notifyLogIpage = notifyLogMapper.pageByParam(page, orderParam);
        for (NotifyLog record : notifyLogIpage.getRecords()) {
            if (Objects.equals(record.getSendType(), 0)) {
                record.setShopName("平台");
            }
        }
        return notifyLogIpage;
    }

    @Override
    public Integer countMsgNum(String orderNumber) {
        return notifyLogMapper.countMsgNum(orderNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendMessage(NotifyLog notifyLog) {
        if (StrUtil.isBlank(notifyLog.getUserMobile()) || StrUtil.isBlank(notifyLog.getParamContent())) {
           return;
        }
        // 修改成已发送
        notifyLog.setStatus(1);
        updateById(notifyLog);
        NotifyTemplateParam param = Json.parseObject(notifyLog.getParamContent(), NotifyTemplateParam.class);
        // 获取对应map
        LinkedHashMap<String, String> smsParam = getSmsParam(param);
        try {

            // 推送短信和公众号消息
            if (Objects.equals(notifyLog.getRemindType(), RemindType.SMS.value())) {
                smsLogService.sendMsgSms(notifyLog.getTemplateCode(), param.getUserMobile(), smsParam);
            }
            if (Objects.equals(notifyLog.getRemindType(), RemindType.MP.value()) && StrUtil.isNotBlank(param.getOpenId())) {
                sendMpMessage(notifyLog.getMpCode(), param);
            }
        } catch (Exception e) {
            log.error(SendType.LAUNCH_REFUND.getDesc() + "：消息推送失败！");
            throw new YamiShopBindException("消息推送失败");
        }
    }

    @Override
    public List<NotifyLog> listUnSendMsgList() {
        return notifyLogMapper.listUnSendMsgList();
    }

    @Override
    public Long countUnreadMsg(String userId) {
        // 未读系统消息数量
        long countUnreadSysMsg = count(new LambdaQueryWrapper<NotifyLog>()
                .eq(NotifyLog::getRemindId, userId)
                .eq(NotifyLog::getStatus, 0)
                .lt(NotifyLog::getSendType, 100)
                .eq(NotifyLog::getRemindType, 3));

        return countUnreadSysMsg;
    }

    @Override
    public IPage<NotifyLog> pageByNotifyLogParam(PageParam<NotifyLog> page, NotifyLog notifyLog) {
        return  notifyLogMapper.pageByNotifyLogParam(page, notifyLog);
    }

    @Override
    public void isReadByShopId(Long shopId) {
        notifyLogMapper.isReadByShopId(shopId);
    }

    @Override
    public void isReadByIds(List<Long> logIds) {
        notifyLogMapper.isReadByIds(logIds);
    }


    /**
     * 发送微信模板信息
     */
    private void sendMpMessage(String mpCode, NotifyTemplateParam param) {
        if (StrUtil.isBlank(param.getUserId()) || StrUtil.isBlank(mpCode)) {
            return;
        }
        WxMpTemplateMessage wxMaUniformMessage = new WxMpTemplateMessage();
        wxMaUniformMessage.setToUser(param.getOpenId());
//        wxMaUniformMessage.setClientMsgId(shopConfig.getWxMp().getAppId());
        // 公众号模板消息所要跳转的小程序
        WxMpTemplateMessage.MiniProgram miniProgram = new WxMpTemplateMessage.MiniProgram();
        miniProgram.setAppid(shopConfig.getWxMiniApp().getAppId());
        miniProgram.setPagePath("pages/user/user");
        wxMaUniformMessage.setMiniProgram(miniProgram);
        //模板id
        wxMaUniformMessage.setTemplateId(mpCode);
        //模板数据集合
        wxMaUniformMessage.setData(getWxMpTemplateDataList(param, param.getShopName()));
        try {
            wxConfig.getWxMpService().getTemplateMsgService().sendTemplateMsg(wxMaUniformMessage);
        } catch (WxErrorException e) {
            //用户未关注公众号，导致的消息发送失败异常
            if (Objects.nonNull(e) && Objects.nonNull(e.getError()) && e.getError().getErrorCode() == WxMsgReturnCode.NO_SUBSCRIBE.value()) {
                log.info("用户（" + param.getUserId() + "）没有关注公众号，导致消息发送失败");
            }
            //其他异常
            else {
                log.error("WxErrorException:", e);
            }
        }
    }


    private List<WxMpTemplateData> getWxMpTemplateDataList(NotifyTemplateParam param, String shopName) {
        Map<Integer, List<WxMpTemplateData>> mpMap = new HashMap<>(24);
        String priceStr = param.getPrice() + "元";
        payMsg(param, mpMap, priceStr);

        refundMsg(param, shopName, mpMap, priceStr);

        deliveryMsg(param, mpMap, priceStr);

        groupMsg(param, mpMap, priceStr);

//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("first", "会员升级通知"));
//        dataList.add(new WxMpTemplateData("keyword1", param.getLevelName()));
//        dataList.add(new WxMpTemplateData("keyword2", "成功！"));
//        dataList.add(new WxMpTemplateData("remark", "感谢您的支持！"));
//        mpMap.put(SendType.MEMBER.getValue(), dataList);

        return mpMap.get(param.getSendType());
    }

    private void groupMsg(NotifyTemplateParam param, Map<Integer, List<WxMpTemplateData>> mpMap, String priceStr) {
        List<WxMpTemplateData> dataList;
        dataList = new ArrayList<>();
        dataList.add(new WxMpTemplateData("character_string3", param.getOrderNumber()));
        dataList.add(new WxMpTemplateData("thing2", param.getProdName()));
        dataList.add(new WxMpTemplateData("amount4", priceStr));
        mpMap.put(SendType.GROUP_FAIL.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMpTemplateData("thing2", param.getProdName()));
        dataList.add(new WxMpTemplateData("time4", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
        mpMap.put(SendType.GROUP_SUCCESS.getValue(), dataList);
//
//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("first", "恭喜你，开团已经成功！"));
//        dataList.add(new WxMpTemplateData("keyword1", param.getProdName()));
//        dataList.add(new WxMpTemplateData("keyword2", priceStr));
//        dataList.add(new WxMpTemplateData("remark", "快去小程序将参团链接分享给好友进行参团吧！"));
//        mpMap.put(SendType.GROUP_START.getValue(), dataList);
    }

    private void deliveryMsg(NotifyTemplateParam param, Map<Integer, List<WxMpTemplateData>> mpMap, String priceStr) {
        List<WxMpTemplateData> dataList;
//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("character_string3", param.getProdName()));
//        dataList.add(new WxMpTemplateData("amount2", priceStr));
//        mpMap.put(SendType.WRITE_OFF.getValue(), dataList);

//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("character_string5", param.getOrderNumber()));
//        dataList.add(new WxMpTemplateData("thing1", param.getProdName()));
//        dataList.add(new WxMpTemplateData("short_thing3", "已确认收货"));
//        dataList.add(new WxMpTemplateData("time4", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
//        mpMap.put(SendType.RECEIPT_ORDER.getValue(), dataList);
//
//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("first", "你的买家已退货，请及时处理"));
//        dataList.add(new WxMpTemplateData("keyword1", param.getOrderNumber()));
//        dataList.add(new WxMpTemplateData("keyword2", param.getRemark()));
//        dataList.add(new WxMpTemplateData("remark", "如有疑问请及时与客服联系！"));
//        mpMap.put(SendType.RETURN_REFUND.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMpTemplateData("character_string3", param.getOrderNumber()));
        dataList.add(new WxMpTemplateData("thing6", param.getProdName()));
        dataList.add(new WxMpTemplateData("thing9", param.getDvyName()));
        dataList.add(new WxMpTemplateData("character_string8", StrUtil.equals(param.getDvyFlowId(),NO_DELIVERY) ? "0" : param.getDvyFlowId()));
        dataList.add(new WxMpTemplateData("time10", DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN)));
        mpMap.put(SendType.DELIVERY.getValue(), dataList);

//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("character_string3", param.getOrderNumber()));
//        dataList.add(new WxMpTemplateData("thing6", param.getProdName()));
//        dataList.add(new WxMpTemplateData("thing16", param.getReceiverName()));
//        dataList.add(new WxMpTemplateData("phone_number12", param.getReceiverMobile()));
//        mpMap.put(SendType.USER_PAY_SUCCESS.getValue(), dataList);
    }

    private void refundMsg(NotifyTemplateParam param, String shopName, Map<Integer, List<WxMpTemplateData>> mpMap, String priceStr) {
        List<WxMpTemplateData> dataList;
        dataList = new ArrayList<>();
        dataList.add(new WxMpTemplateData("character_string11", param.getOrderNumber()));
        dataList.add(new WxMpTemplateData("thing3", param.getProdName()));
        dataList.add(new WxMpTemplateData("amount9", priceStr));
        mpMap.put(SendType.AGREE_REFUND.getValue(), dataList);

        dataList = new ArrayList<>();
        dataList.add(new WxMpTemplateData("number6", param.getOrderNumber()));
        dataList.add(new WxMpTemplateData("thing10", param.getProdName()));
        dataList.add(new WxMpTemplateData("amount7", priceStr));
        mpMap.put(SendType.REFUSE_REFUND.getValue(), dataList);

//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("first", "您有退款单即将超时，请及时联系商家处理"));
//        dataList.add(new WxMpTemplateData("keyword1", shopName));
//        dataList.add(new WxMpTemplateData("keyword2", "1笔"));
//        dataList.add(new WxMpTemplateData("remark", "如有疑问请及时与客服联系！"));
//        mpMap.put(SendType.REFUND_OUT_TIME.getValue(), dataList);
//
//        dataList = new ArrayList<>();
//        dataList.add(new WxMpTemplateData("character_string11", param.getOrderNumber()));
//        dataList.add(new WxMpTemplateData("thing3", param.getProdName()));
//        dataList.add(new WxMpTemplateData("amount9", priceStr));
//        mpMap.put(SendType.LAUNCH_REFUND.getValue(), dataList);
    }

    private void payMsg(NotifyTemplateParam param, Map<Integer, List<WxMpTemplateData>> mpMap, String priceStr) {
        Date createTime = Objects.isNull(param.getCreateTime()) ? new Date() : param.getCreateTime();
        String prodName = StrUtil.isBlank(param.getProdName()) ? "商城商品" : param.getProdName();
//        String firstData = "亲爱的" + param.getNickName() + ",您在商城购买的宝贝还未付款哦！为确保您心爱的宝贝早日启程、顺利抵达，记得尽早付款哦！";
//        dataList.add(new WxMpTemplateData("first", firstData));
//        dataList.add(new WxMpTemplateData("keyword1", param.getOrderNumber()));
//        dataList.add(new WxMpTemplateData("keyword2", DateUtil.format(createTime, DatePattern.NORM_DATETIME_PATTERN)));
//        dataList.add(new WxMpTemplateData("keyword3", prodName));
//        dataList.add(new WxMpTemplateData("remark", "请您及时付款以免订单过期。"));
//        mpMap.put(SendType.PRESS_PAY.getValue(), dataList);

        List<WxMpTemplateData> dataList = new ArrayList<>();
        dataList.add(new WxMpTemplateData("character_string2", param.getOrderNumber()));
        dataList.add(new WxMpTemplateData("thing3", prodName));
        dataList.add(new WxMpTemplateData("amount5", priceStr));
        dataList.add(new WxMpTemplateData("time6", DateUtil.format(createTime, DatePattern.NORM_DATETIME_PATTERN)));
        mpMap.put(SendType.PAY_SUCCESS.getValue(), dataList);
    }

    private LinkedHashMap<String, String> getSmsParam(NotifyTemplateParam param) {
        LinkedHashMap<String, String> smsParam = new LinkedHashMap<>(20);
        smsParam.put("orderNumber", param.getOrderNumber());
        smsParam.put("shopName", param.getShopName());
        smsParam.put("prodName", param.getProdName());
        if (StrUtil.isBlank(param.getNickName())) {
            smsParam.put("nickName", "用户");
        } else {
            smsParam.put("nickName", param.getNickName());
        }
        smsParam.put("levelName", param.getLevelName());
        smsParam.put("cancelTime", param.getCancelTime());
        smsParam.put("price", String.valueOf(param.getPrice()));
        smsParam.put("dvyFlowId", param.getDvyFlowId());
        smsParam.put("stationName", param.getStationName());
        smsParam.put("dvyName", param.getDvyName());
        smsParam.put("dvyTime", DateUtil.format(param.getDvyTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        smsParam.put("day", String.valueOf(Constant.MAX_REFUND_APPLY_TIME));
        smsParam.put("hour", String.valueOf(param.getHour()));
        smsParam.put("date", DateUtil.format(param.getDvyTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        return smsParam;
    }
}
